/**
 * 
 * The CommunicationProtocol class handles all requests from other clients or the server.
 * 
 * Author: Matthias Van Eeghem <matthias@van-eeghem.com>
 * All rights reserved.
 * 
 */

package com.bomberman.connection;

import com.bomberman.Main;
import com.bomberman.bomb.Bomb;
import com.bomberman.bomb.BombManager;
import com.bomberman.brick.Brick;
import com.bomberman.brick.BrickManager;
import com.bomberman.player.Player;
import com.bomberman.player.PlayerManager;

public class CommunicationProtocol 
{
	// Holds the above-laying connection manager object
	ConnectionManager connectionManager = null;
	
	/**
	 * The constructor of the CommunicationProtocol.
	 * 
	 * @param connectionManager The above laying connection
	 */
	public CommunicationProtocol(ConnectionManager connectionManager)
	{
		this.connectionManager = connectionManager;
	}
	
	/**
	 * This method handles any requests from other clients or the server.
	 *
	 * @param data
	 */
	public void handleData(String data)
	{
		// Split the request into the packet ID and the parameters
		String[] dataSplit = data.split(" ", 2);
		String packetID = dataSplit[0];
		
		// Which packet ID are we dealing with?
		switch(packetID)
		{
			// The client receives the list of all bricks when he connects
			case "FIELD":
			{
				generateField(dataSplit[1]);
				break;
			}
			
			// The player receives this packet when a new player connects
			case "SPAWN_PLAYERS":
			{
				spawnPlayers(dataSplit[1]);
				break;
			}
			
			// Received when a player moves
			case "MOVE":
			{
				movePlayer(dataSplit[1]);
				break;
			}
			
			// Received when a new bomb is placed
			case "ADD_BOMB":
			{
				addBomb(dataSplit[1]);
				break;
			}
			
			// The client receives this packet from the server when he connects
			// The sever assigns an ID and then sends it back to the player
			case "YOUR_ID":
			{
				spawnLocalPlayer(dataSplit[1]);
				break;
			}
			
			// If we get here, it's an unknown packet id
			default:
			{
				System.out.println("Unknown packet ID: " + packetID);
				break;
			}
		}
	}
	
	/**
	 * This method handles a new connection from the client to the server.
	 * 
	 * @param playerName The name of the player that connected
	 * @param playerID The playerid that the server assigned to the player
	 */
	public void handleNewConnection(String playerName, int playerID)
	{
		// Get an empty location for that player
		int row = PlayerManager.getSpawnPositionForID(playerID).getRow();
		int column = PlayerManager.getSpawnPositionForID(playerID).getColumn();
		
		// Spawn the player
		PlayerManager.addPlayer(playerName, row, column, playerID);
		
		// Inform the other players this one has spawned
		connectionManager.sendDataToAllPlayersExcept(playerID, "SPAWN_PLAYERS " + playerName + "," + row + "," + column + "," + playerID);
	}
	
	/**
	 * Called when the local player should spawn
	 * 
	 * @param data
	 */
	private void spawnLocalPlayer(String data)
	{
		String[] playerData = data.split(" ");
		
		PlayerManager.addPlayer(Main.playerName, Integer.parseInt(playerData[0]), Integer.parseInt(playerData[1]), Integer.parseInt(playerData[2]));
	}
	
	/**
	 * If the client connects, it receives the field as a string from the server.
	 * This is the method that generates the field from the string.
	 * 
	 * (Client only method)
	 * 
	 * @param data The field has the following format: "0,0, 0,5 3,1" this means
	 * there are bricks supposed to be at row 0 column 0, row 0 column 5, row 3 column 1. 
	 */
	private void generateField(String data)
	{
		// Split the brick list into bricks (so each brick has a row,column format)
		String[] brickList = data.split(" ");
		
		// Loop through all the bricks
		for(String brick : brickList)
		{
			// Split all bricks into their row and column
			String[] brickData = brick.split(",");
			
			// Add the brick
			BrickManager.addBrick(new Brick(Integer.parseInt(brickData[0]), Integer.parseInt(brickData[1])));
		}
	}
	
	/**
	 * After the client connects, it also receives a list of players that are already connected.
	 *
	 * (Client and server method)
	 * 
	 * @param data The data has the following format: "name1,row1,column1,id1 name2,row2,column2,id2"
	 */
	private void spawnPlayers(String data)
	{
		// Split the data into players
		String[] playerList = data.split(" ");
		
		// Loop through all the players
		for(String player : playerList)
		{
			// Split the data for each player
			String[] playerData = player.split(",");
			
			// Add the player
			PlayerManager.addPlayer(playerData[0], Integer.parseInt(playerData[1]), Integer.parseInt(playerData[2]), Integer.parseInt(playerData[3]));
		}
	}
	
	/**
	 * This method moves the player to a different position. This method takes 4 parameters: "LEFT", "RIGHT", "UP" and "DOWN"
	 * 
	 * (Client and server method)
	 * 
	 * @param data
	 */
	private void movePlayer(String data)
	{
		String[] moveData = data.split(" ");
		
		int playerID = Integer.parseInt(moveData[1]);
		
		// Get the player to move from the ID parameter
		Player playerToMove = PlayerManager.getPlayerList().get(playerID);
		
		if(connectionManager.isHost())
			// Inform the other players this player has moved
			connectionManager.sendDataToAllPlayersExcept(playerID, "MOVE " + moveData[0] + " " + playerID);
		
		// Which move direction are we dealing with?
		switch(moveData[0])
		{
			case "UP":
			{
				playerToMove.moveUp();
				break;
			}
			
			case "DOWN":
			{
				playerToMove.moveDown();
				break;
			}
			
			case "LEFT":
			{
				playerToMove.moveToLeft();
				break;
			}
			
			case "RIGHT":
			{
				playerToMove.moveToRight();
				break;
			}
			
			// No valid move direction found
			default:
			{
				System.out.println(moveData[0] + "is an unknown move direction.");
				break;
			}
		}
	}
	
	/**
	 * Adds a bomb to the game.
	 * 
	 * (Client and server method)
	 * 
	 * @param data The only parameter is the player id to place the bomb for
	 */
	private void addBomb(String data)
	{
		int playerID = Integer.parseInt(data);
		Player player = PlayerManager.getPlayerList().get(playerID);
		
		BombManager.add(new Bomb(player, player.getRows().get(0), player.getColumns().get(0)));	
		
		if(connectionManager.isHost())
			// Inform the other players this player has moved
			connectionManager.sendDataToAllPlayersExcept(playerID, "ADD_BOMB " + playerID);
	}
}
